package com.stock.common.codec;

import com.stock.common.collect.ListUtils;
import com.stock.common.exception.BusinessException;
import com.stock.common.lang.StringUtils;
import org.apache.commons.codec.DecoderException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.binary.Hex;
import org.apache.commons.text.StringEscapeUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class EncodeUtils {

    public static final String UTF_8 = "UTF-8";

    private static final Logger logger = LoggerFactory.getLogger(EncodeUtils.class);
    private static final char[] BASE62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz".toCharArray();

    /**
     * Hex编码.
     */
    public static String encodeHex(byte[] input) {
        return new String(Hex.encodeHex(input));
    }

    /**
     * Hex解码.
     */
    public static byte[] decodeHex(String input) {
        try {
            return Hex.decodeHex(input.toCharArray());
        } catch (DecoderException e) {
            throw new BusinessException(e);
        }
    }

    /**
     * Base64编码.
     */
    public static String encodeBase64(byte[] input) {
        return new String(Base64.encodeBase64(input));
    }

    /**
     * Base64编码.
     */
    public static String encodeBase64(String input) {
        if (StringUtils.isBlank(input)){
            return StringUtils.EMPTY;
        }
        return new String(Base64.encodeBase64(input.getBytes(StandardCharsets.UTF_8)));
    }

    /**
     * Base64解码.
     */
    public static byte[] decodeBase64(String input) {
        return Base64.decodeBase64(input.getBytes(StandardCharsets.UTF_8));
    }

    /**
     * Base64解码.
     */
    public static String decodeBase64String(String input) {
        if (StringUtils.isBlank(input)){
            return StringUtils.EMPTY;
        }
        return new String(Base64.decodeBase64(input.getBytes(StandardCharsets.UTF_8)), StandardCharsets.UTF_8);
    }

    /**
     * Base62编码。
     */
    public static String encodeBase62(byte[] input) {
        char[] chars = new char[input.length];
        for (int i = 0; i < input.length; i++) {
            chars[i] = BASE62[((input[i] & 0xFF) % BASE62.length)];
        }
        return new String(chars);
    }

    /**
     * Html 转码.
     */
    public static String encodeHtml(String html) {
        return StringEscapeUtils.escapeHtml4(html);
    }

    /**
     * Html 解码.
     */
    public static String decodeHtml(String htmlEscaped) {
        return StringEscapeUtils.unescapeHtml4(htmlEscaped);
    }

    /**
     * Xml 转码.
     */
    public static String encodeXml(String xml) {
        return StringEscapeUtils.escapeXml10(xml);
    }

    /**
     * Xml 解码.
     */
    public static String decodeXml(String xmlEscaped) {
        return StringEscapeUtils.unescapeXml(xmlEscaped);
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     */
    public static String encodeUrl(String part) {
        return encodeUrl(part, EncodeUtils.UTF_8);
    }

    /**
     * URL 编码, Encode默认为UTF-8.
     */
    public static String encodeUrl(String part, String encoding) {
        if (part == null){
            return null;
        }
        try {
            return URLEncoder.encode(part, StringUtils.isNotBlank(encoding) ? encoding : EncodeUtils.UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw new BusinessException(e);
        }
    }

    /**
     * URL 解码, Encode默认为UTF-8.
     */
    public static String decodeUrl(String part) {
        return decodeUrl(part, EncodeUtils.UTF_8);
    }

    /**
     * URL 解码, Encode默认为UTF-8.
     */
    public static String decodeUrl(String part, String encoding) {
        if (part == null){
            return null;
        }
        try {
            return URLDecoder.decode(part, StringUtils.isNotBlank(encoding) ? encoding : EncodeUtils.UTF_8);
        } catch (UnsupportedEncodingException e) {
            throw new BusinessException(e);
        }
    }

    /**
     * URL 解码（两次）, Encode默认为UTF-8.
     */
    public static String decodeUrl2(String part) {
        return decodeUrl(decodeUrl(part));
    }

    // 预编译XSS过滤正则表达式
    private static final List<Pattern> xssPatterns = ListUtils.newArrayList(
            Pattern.compile("(<\\s*(script|link|style|iframe)([\\s\\S]*?)(>|<\\/\\s*\\1\\s*>))|(</\\s*(script|link|style|iframe)\\s*>)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("\\s*(href|src)\\s*=\\s*(\"\\s*(javascript|vbscript|data):[^\"]+\"|'\\s*(javascript|vbscript|data):[^']+'|(javascript|vbscript|data):[^\\s]+)\\s*(?=>)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("\\s*/?\\s*on[a-zA-Z]+\\s*=\\s*(['\"]?)(.*?)\\1(?=\\s|>|/>)", Pattern.CASE_INSENSITIVE),
            Pattern.compile("(eval\\((.*?)\\)|expression\\((.*?)\\))", Pattern.CASE_INSENSITIVE),
            Pattern.compile("^(javascript:|vbscript:)", Pattern.CASE_INSENSITIVE)
    );

    // 预编译SQL过滤正则表达式
    private static final Pattern sqlPattern = Pattern.compile(
            "(?:')|(?:--)|(/\\*(?:.|[\\n\\r])*?\\*/)|((extractvalue|updatexml|if|mid|database|rand|user)([\\s]*?)\\()"
                    + "|(\\b(select|update|and|or|delete|insert|trancate|substr|ascii|declare|exec|count|master|into"
                    + "|drop|execute|case when|sleep|union|load_file)\\b)", Pattern.CASE_INSENSITIVE);
    private static final Pattern simplePattern = Pattern.compile("[a-z0-9_\\.\\, ]*", Pattern.CASE_INSENSITIVE);
    private static final Pattern columnNamePattern = Pattern.compile("[a-z0-9_\\.`\"\\[\\]]*", Pattern.CASE_INSENSITIVE);

    /**
     * SQL过滤，防止注入，传入参数输入有select相关代码，替换空。
     * @author ThinkGem
     */
    public static String sqlFilter(String text){
        return sqlFilter(text, "common");
    }

    /**
     * SQL过滤，防止注入，传入参数输入有select相关代码，替换空。
     * @author ThinkGem
     */
    public static String sqlFilter(String text, String source){
        if (text != null){
            String value = text;
            if (StringUtils.inString(source, "simple", "orderBy")) {
                Matcher matcher = simplePattern.matcher(value);
                if (!matcher.matches()) {
                    value = StringUtils.EMPTY;
                }
            } else if (StringUtils.inString(source, "columnName")) {
                Matcher matcher = columnNamePattern.matcher(value);
                if (!matcher.matches()) {
                    value = StringUtils.EMPTY;
                }
            } else {
                Matcher matcher = sqlPattern.matcher(value);
                if (matcher.find()) {
                    value = matcher.replaceAll(StringUtils.EMPTY);
                }
            }
            if (logger.isWarnEnabled() && !value.equals(text)){
                logger.info("sqlFilter: {}   <=<=<=   {}   source: {}", value, text, source);
                return StringUtils.EMPTY;
            }
            return value;
        }
        return null;
    }

    // 对邮箱和手机号进行安全处理
    private static final Pattern emailPattern = Pattern.compile("([\\w\\W]?)([\\w\\W]+)([\\w\\W])(@[\\w\\W]+)");
    private static final Pattern mobilePattern = Pattern.compile("(\\d{3})(\\d+)(\\d{3})");

    /**
     * 手机号码进行掩码处理
     */
    public static String mobileMask(String mobile){
        if (StringUtils.isBlank(mobile)){
            return mobile;
        }
        return mobilePattern.matcher(mobile).replaceAll("$1****$3");
    }

    /**
     * 对电子邮箱进行掩码处理
     */
    public static String emailMask(String email){
        if (StringUtils.isBlank(email)){
            return email;
        }
        return emailPattern.matcher(email).replaceAll("$1****$3$4");
    }

}
